package cpr;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.Writer;
import java.util.Calendar;
import java.util.Collection;
import java.util.Comparator;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class Printer {
    static BufferedWriter secordWriter = null;
    static String secondWriterFilename = null;
    private static void setSecordWriter(BufferedWriter w) {
        secordWriter = w;
    }
    
    private static Writer getSecondWriter() {
    	if (secondWriterFilename==null) return null;
    	if (secordWriter!=null) return secordWriter;
    	open();
    	return secordWriter;
    }
    
    public static void open() {
    	  try {
          	File f = new File(secondWriterFilename);
          	if (f.exists()) {
          		throw new RuntimeException("file "+secondWriterFilename+" already exists.");
          	}
          	//println("Second output changed: "+_secordWriterFilename);
          	Writer wr = new FileWriter(secondWriterFilename);
          	secordWriter = new BufferedWriter(wr);
          } catch (Exception ex) {
           ex.printStackTrace();   
          }
    }
    
    public static void setSecordWriter(String fileName) {
    	close();
    	secondWriterFilename = fileName;
    }
    public static void close() {
        if (secordWriter!=null) {
            try {
            	BufferedWriter c = secordWriter;
            	secordWriter = null;
            	c.flush();
                c.close();
            } catch (Exception ex) {
            	ex.printStackTrace();
            }
        } 	
    }
    public static void print(String str) {
        System.out.print(str);
        System.out.flush();
        if (secordWriter!=null) {
        	
            try {
                secordWriter.write(str);
                secordWriter.flush();
            } catch (Exception ex) {
            	ex.printStackTrace();
                
            }
        }
    }
    
    public static void printlnToSecondaryPrinter(String str) {
        if (secordWriter!=null) {
            try {
                secordWriter.write(str+"\n");
                secordWriter.flush();
            } catch (Exception ex) {
                ex.printStackTrace();
                
            }
        }
    }
    public static void println(String str) {
        print(str+"\n");
    }
    
    public static void println() {
        print("\n");
    }
    
    
    public static void printInteger(int i) {
    	if (i<10000000) print(" ");
    	if (i<1000000) print(" ");
    	if (i<100000) print(" ");
    	if (i<10000) print(" ");
    	if (i<1000) print(" ");
    	if (i<100) print(" ");
    	if (i<10) print(" ");
    	print(""+i);
    }
    
    
    public static String currDate() {
    	return currDate(System.currentTimeMillis());
    }
   public static String currDate(long millis) {
    	Calendar c = new GregorianCalendar();
    	c.setTimeInMillis(millis);
    	int hour = c.get(Calendar.HOUR_OF_DAY);
    	int min = c.get(Calendar.MINUTE);
    	int sec = c.get(Calendar.SECOND);
    	int msec = c.get(Calendar.MILLISECOND);
    	return ""+hour+":"+min+":"+sec+":"+msec;
    }
   public static String printTime(long millis) {
   	Calendar c = new GregorianCalendar();
   	c.setTimeInMillis(millis);
   	int min = c.get(Calendar.MINUTE);
   	int sec = c.get(Calendar.SECOND);
   	int msec = c.get(Calendar.MILLISECOND);
   	return ""+min+":"+sec+":"+msec;
   }
   
    public static void print(boolean verbose, String str) {
        if (verbose) {
            print(str);
        }
    }
    public static void println(boolean verbose, String str) {
        if (verbose) {
            println(str);
        }
    }
    public static String printScore(String score) {
        int[] sc =Utils.decayScore(Integer.parseInt(score),Rule.HL_SCORE);
        return "{"+sc[0]+","+sc[1]+","+sc[2]+","+sc[3]+","+sc[4]+"}";
    }
    
    public static void print(Set list) {
        for (Iterator iter = list.iterator(); iter.hasNext();) {
            Object element = iter.next();
            print(element+ " ");
        } 
    }
    public static void print(List list) {
        for (Iterator iter = list.iterator(); iter.hasNext();) {
            Object element = iter.next();
            println(element.toString());  
        } 
    }
    public void print(Map map, String name) {
        println(name+"="+map.size());  
        for (Iterator iter = map.keySet().iterator(); iter.hasNext();) {
            String element = (String) iter.next();
            println(element+ " "+ map.get(element));  
        } 
        println("");     	
    }
    
 
    /*
    public static ObjectPrinter createRuleHTMLTableLinePrinter() {
        ObjectPrinter p = new AbstractObjectPrinter() {
            public String objToString(Object obj) {
                Rule mr = (Rule)obj;
                StringBuffer sb = new StringBuffer();
                sb.append("<tr>");
                sb.append("<td>");
                sb.append(mr.ruleNr);
                sb.append("</td>");

                sb.append("<td>");
                sb.append(mr.salesOrg);
                sb.append("</td>");
                sb.append("<td>");
                sb.append(mr.soldTo);
                sb.append("</td>");
                sb.append("<td>");
                sb.append(mr.shipTo);
                sb.append("</td>");
                sb.append("<td>");
                sb.append(mr.ducpr);
                sb.append("</td>");
                sb.append("<td>");
                sb.append(mr.attrName);
                sb.append("</td>");
                sb.append("<td>");
                sb.append(mr.attrValue);
                sb.append("</td>");
                sb.append("<td>");
                sb.append(mr.score);
                sb.append("</td>");
                sb.append("</tr>");
                return sb.toString();
            }
        };
        return p;
    }    
    */
    
    interface ObjectExtractor {
        public Object getValue(Object target);
    }
    
//    static class ObjectExtractorComparator implements Comparator {
//        ObjectExtractor oe;
//        public ObjectExtractorComparator(ObjectExtractor oe) {
//            this.oe = oe;
//        }
//        public int compare(Object o1, Object o2) {
//            return oe.getValue(o1).toString().compareTo(oe.getValue(o2).toString());
//            
//        }
//        public boolean equals(Object obj) {
//            return oe.getValue(obj).equals(oe.getValue(this).toString());
//        }
//    } 


    public static ObjectPrinter createCollectionPrinter(final ObjectExtractor elementExtr, final String separator) {
        ObjectPrinter p = new AbstractObjectPrinter() {
    		public String objToString(Object set) {
    			StringBuffer sb = new StringBuffer();
    	        for (Iterator iter = ((Collection)set).iterator(); iter.hasNext();) {
    	            Object element = (Object) iter.next();
    	            sb.append(elementExtr.getValue(element)+ separator);
    	        } 
    	        return sb.toString();
    	    }
    	};
    	return p;
    }
    
    public static ObjectPrinter createCollectionAndSizePrinter(final String separator) {
        ObjectPrinter p = new AbstractObjectPrinter() {
            public String objToString(Object set) {
                StringBuffer sb = new StringBuffer();
                sb.append("["+((Collection)set).size()+"] ");
                for (Iterator iter = ((Collection)set).iterator(); iter.hasNext();) {
                    Object element = (Object) iter.next();
                    sb.append(element+ separator);
                } 
                return sb.toString();
            }
        };
        return p;
    }    
    public static ObjectPrinter createCollectionSizePrinter() {
        ObjectPrinter p = new AbstractObjectPrinter() {
    		public String objToString(Object set) {
    			StringBuffer sb = new StringBuffer();
    			sb.append(((Collection)set).size());
    	        return sb.toString();
    	    }
    	};
    	return p;
    }
    public static ObjectPrinter createStringPrinter() {
        ObjectPrinter p = new StringPrinter();
        return p;
    }
}

interface MacroRulePrinter {
    
}

class StringPrinter extends AbstractObjectPrinter {
    StringBuffer sb = new StringBuffer();
    public void printObject(Object obj) {
        sb.append(obj.toString());
    }
    public void printObject(String prefix, Object obj, String postfix) {
        sb.append(objToString(prefix, obj, postfix));
    }   

    public String objToString(Object obj) {
        return obj.toString();
    }
    public String toString() {
        return sb.toString();
    }
    
}

interface ObjectPrinter {
    public void printObject(Object obj);
    public void printObject(String prefix, Object obj, String postfix);
    public String objToString(Object obj);
    public String objToString(String prefix, Object obj, String postfix);
}

abstract class AbstractObjectPrinter implements ObjectPrinter {
    public void printObject(Object obj) {
        Printer.print(objToString(obj));
    }
    public String objToString(String prefix, Object obj, String postfix) {
        StringBuffer sb = new StringBuffer();
        sb.append(prefix);
        sb.append(objToString(obj));
        sb.append(postfix); 
        return sb.toString();
    }
    public void printObject(String prefix, Object obj, String postfix) {
        Printer.print(objToString(prefix, obj, postfix));
    }   
}
